#ifndef __FIBER_SCHEDULER_H__
#define __FIBER_SCHEDULER_H__

#include <atomic>               // 原子变量（线程安全计数）
#include <functional>           // 函数对象（存储任务回调）
#include <list>                 // 任务队列（链表实现，支持高效插入删除）
#include <memory>               // 智能指针（管理对象生命周期）
#include <vector>               // 动态数组（存储线程池、线程ID）
#include "fiber.h"              // 协程类（调度的核心对象）
#include "mutex.h"              // 自定义互斥锁（可能是封装了系统锁）
#include "thread.h"             // 线程类（工作线程封装）
#include "utils.h"              // 工具函数（如日志、断言等）

namespace fiber 
{
// 调度任务封装类：统一封装“协程”或“函数”为可调度的任务 
// 协程本身就函数和函数运行状态的组合
class SchedulerTask {
public:
    friend class Scheduler;  // 允许调度器直接访问私有成员

    // 默认构造：任务为空，不指定线程
    SchedulerTask() :m_fiber(nullptr), m_cb(nullptr), m_thread(-1) {}

    // 构造函数：封装协程任务，指定执行线程
    // 参数：f=协程指针，t=目标线程ID（-1表示任意线程）
    SchedulerTask(Fiber::ptr f, int t) : m_fiber(f), m_thread(t) {}

    // 构造函数：通过指针交换获取协程（减少拷贝），指定执行线程
    SchedulerTask(Fiber::ptr* f, int t) {
        m_fiber.swap(*f);  // 交换指针，避免智能指针的引用计数操作
        m_thread = t;
    }

    // 构造函数：封装函数任务（非协程的普通函数），指定执行线程
    SchedulerTask(std::function<void()> f, int t) {
        m_cb = f;  // 存储函数对象
        m_thread = t;
    }

    // 构造函数：通过指针交换获取函数（减少拷贝），指定执行线程
    SchedulerTask(std::function<void()>* f, int t) {
        m_cb.swap(*f);  // 存储函数对象
        m_thread = t;
    }

    // 清空任务：重置所有成员，释放资源
    void reset() {
        m_fiber = nullptr;  // 释放协程
        m_cb = nullptr;     // 释放函数
        m_thread = -1;      // 重置线程ID
    }

private:
    Fiber::ptr m_fiber;          // 协程任务（可能为nullptr，此时执行cb_）
    std::function<void()> m_cb;  // 函数任务（可能为nullptr，此时执行fiber_）
    int m_thread;                // 目标执行线程ID（-1表示不指定，由调度器分配）
};


// N→M协程调度器：管理M个线程，调度N个协程在这些线程上执行
class Scheduler {
public:
    using ptr = std::shared_ptr<Scheduler>;  // 调度器智能指针类型

    /**
     * 构造函数：初始化调度器
     * @param threads 工作线程数量（不包含调用者线程，除非use_caller=true）
     * @param use_caller 是否使用创建调度器的线程作为工作线程之一
     * @param name 调度器名称（用于调试和日志）
     */
    Scheduler(size_t threads = 1, bool use_caller = true, const std::string &name = "Scheduler");

    /**
     * 析构函数：虚函数，确保子类析构时正确释放资源
     */
    virtual ~Scheduler();

    /**
     * 获取调度器名称
     */
    const std::string& getName() const { return m_name; }

    /**
     * 静态方法：获取当前线程关联的调度器
     */
    static Scheduler* GetThis();

    /**
     * 静态方法：获取当前线程的“调度协程”
     * （调度器在每个工作线程上都有一个调度协程，负责从任务队列取任务执行）
     */
    static Fiber* GetSchedulerFiber();

    /**
     * 添加调度任务（模板方法，支持协程或函数任务）
     * @tparam TaskType 任务类型（Fiber::ptr 或 std::function<void()>）
     * @param task 任务对象（协程或函数）
     * @param thread 目标执行线程ID（-1表示任意空闲线程）
     */
    template <class TaskType>
    void scheduler(TaskType task, int thread = -1) {
        bool isNeedTickle = false;  // 是否需要唤醒空闲线程
        {
            Mutex::Lock lock(m_mutex);  // 加锁保护任务队列
            // 无锁添加任务，并返回“添加前队列是否为空”
            isNeedTickle = schedulerNoLock(task, thread);
        }

        // 若添加任务前队列为空，说明可能有线程处于idle状态(空闲状态)，需要唤醒
        if (isNeedTickle) {
            tickle();  // 唤醒idle协程（通知有新任务）
        }
    }

    /**
     * 启动调度器：创建并启动工作线程
     */
    void start();

    /**
     * 停止调度器：等待所有任务执行完毕，销毁工作线程
     */
    void stop();

protected:
    /**
     * 通知调度器有新任务（唤醒空闲线程）
     * 子类可重写，实现不同的唤醒策略（如信号量、条件变量等）
     */
    virtual void tickle();

    /**
     * 协程调度主函数：每个工作线程的入口逻辑
     * 循环从任务队列取任务，执行协程或函数，无任务时执行idle
     */
    virtual void run();

    /**
     * 空闲协程逻辑：当任务队列为空时执行
     * 子类可重写，实现自定义的空闲处理（如休眠、等待信号等）
     */
    virtual void idle();

    /**
     * 判断调度器是否可以停止
     * @return true=可以停止（所有任务执行完毕且无活跃线程）
     */
    virtual bool stopping();

    /**
     * 设置当前线程的关联调度器（线程局部存储）
     */
    void setThis();

    /**
     * 检查是否有空闲线程
     */
    bool isHasIdleThreads() { return m_idleThreadCnt > 0; }

private:
    /**
     * 无锁添加任务（内部调用，需外部加锁）
     * @tparam TaskType 任务类型
     * @param t 任务对象
     * @param thread 目标线程ID
     * @return 添加前队列是否为空（为空则需要唤醒线程）
     */
    template <class TaskType>
    bool schedulerNoLock(TaskType t, int thread) {
        bool isNeedTickle = m_tasks.empty();    // 记录添加前队列是否为空
        SchedulerTask task(t, thread);          // 封装任务
        if (task.m_fiber || task.m_cb) {        // 仅添加有效任务（协程或函数非空）
            m_tasks.push_back(task);            // 加入任务队列
        }
        return isNeedTickle;  // 返回是否需要唤醒线程
    }

    std::string m_name;         // 调度器名称（调试用）
    Mutex m_mutex;              // 保护任务队列的互斥锁
    std::vector<Thread::ptr> m_threadPool;  // 工作线程池（存储所有工作线程）
    std::list<SchedulerTask> m_tasks;       // 任务队列（待执行的协程/函数）
    std::vector<int> m_threadIds;           // 工作线程ID列表（用于判断任务目标线程是否有效）
    size_t m_threadCnt = 0;                 // 工作线程(也就是额外线程)数量（不包含use_caller的线程）
    std::atomic<size_t> m_activeThreadCnt = {0}; // 活跃线程数（正在执行任务的线程）
    std::atomic<size_t> m_idleThreadCnt = {0};   // 空闲线程数（处于idle状态的线程）
    bool m_isUseCaller;                  // 是否使用创建调度器的线程作为工作线程
    Fiber::ptr m_schedulerFiber;         // 若use_caller=true，存储调用者线程的调度协程
    int m_rootThread = 0;                // 若use_caller=true，存储调用者线程的ID
    bool m_isStopped = false;            // 调度器是否已停止
};              

}  // namespace fiber

#endif  // __FIBER_SCHEDULER_H__